/** 
    @file vector.cpp
    @brief Vector and point class implementations
*/
#include "vector.hpp"
#include "util.hpp"

template <class T>
pm3::VEC2<T>::VEC2 (T X, T Y) {
    x = X;
    y = Y;
}

template <class T>
T& pm3::VEC2<T>::operator[] (const int &i) {
    return (i == 0 ? x : y);
}

template <class T>
pm3::VEC2<T>& pm3::VEC2<T>::operator= (const pm3::VEC2<T> &v) {
    x = v.x;
    y = v.y;
    return *this;
}

template <class T>
bool pm3::VEC2<T>::operator== (const pm3::VEC2<T> &v) const {
    return (x < v.x + 0.0001f && x > v.x - 0.0001f &&
            y < v.y + 0.0001f && y > v.y - 0.0001f);
}

template <class T>
bool pm3::VEC2<T>::operator!= (const pm3::VEC2<T> &v) const {
    return !(*this == v);
}

template <class T>
pm3::VEC2<T> pm3::VEC2<T>::operator+ (const pm3::VEC2<T> &v) const {
    return pm3::VEC2<T> (x + v.x, y + v.y);
}

template <class T>
pm3::VEC2<T> pm3::VEC2<T>::operator- (const pm3::VEC2<T> &v) const {
    return pm3::VEC2<T> (x - v.x, y - v.y);
}

template <class T>
pm3::VEC2<T> pm3::VEC2<T>::operator- (void) const {
    return pm3::VEC2<T> (-x, -y);
}

template <class T>
pm3::VEC2<T>& pm3::VEC2<T>::operator+= (const pm3::VEC2<T> &v) {
    x += v.x;
    y += v.y;
    return *this;
}

template <class T>
pm3::VEC2<T>& pm3::VEC2<T>::operator-= (const pm3::VEC2<T> &v) {
    x -= v.x;
    y -= v.y;
    return *this;
}

template <class T>
pm3::VEC2<T> pm3::VEC2<T>::operator* (const T &t) const {
    return pm3::VEC2<T> (x * t, y * t);
}

template <class T>
T pm3::VEC2<T>::operator* (const pm3::VEC2<T> &v) const {
    return (x * v.x + y * v.y);
}

template <class T>
pm3::VEC2<T> pm3::VEC2<T>::operator/ (const T &t) const {
    return VEC2<T> (x / t, y / t);
}

template <class T>
pm3::VEC2<T>& pm3::VEC2<T>::operator*= (const T &t) {
    x *= t;
    y *= t;
    return *this;
}

template <class T>
pm3::VEC2<T>& pm3::VEC2<T>::operator/= (const T &t) {
    x /= t;
    y /= t;
    return *this;
}

pm3::GRID_POINT::GRID_POINT() {
    m_layer = 0;
}

pm3::GRID_POINT::GRID_POINT( int i_layer, int i_x, int i_y ) {
    m_layer = i_layer;
    m_point.x = i_x;
    m_point.y = i_y;
}

pm3::GRID_POINT::GRID_POINT( int i_layer, pm3::VEC2I v ) {
    m_layer = i_layer;
    m_point = v;
}

pm3::GRID_POINT::GRID_POINT( const Ogre::Vector3 &r_v ) {
    m_layer = (int) pm3::util::round( r_v.y );
    m_point.x = (int) pm3::util::round( r_v.x );
    m_point.y = (int) pm3::util::round( r_v.z );
}

pm3::GRID_POINT& pm3::GRID_POINT::operator= (const pm3::GRID_POINT &p) {
    m_layer = p.m_layer;
    m_point = p.m_point;
    return *this;
}

pm3::GRID_POINT& pm3::GRID_POINT::operator= (const Ogre::Vector3 &r_v) {
    m_layer = (int) pm3::util::round( r_v.y );
    m_point.x = (int) pm3::util::round( r_v.x );
    m_point.y = (int) pm3::util::round( r_v.z );
    return *this;
}

bool pm3::GRID_POINT::operator== (const GRID_POINT &p) const {
    return ( m_layer == p.m_layer && m_point == p.m_point );
}

bool pm3::GRID_POINT::operator!= (const GRID_POINT &p) const {
    return ( m_layer != p.m_layer || m_point != p.m_point );
}

pm3::GRID_POINT pm3::GRID_POINT::operator+ (const pm3::GRID_POINT &p) const {
    return pm3::GRID_POINT( m_layer + p.m_layer, m_point + p.m_point );
}

pm3::GRID_POINT pm3::GRID_POINT::operator- (void) const {
    return pm3::GRID_POINT( -m_layer, -m_point );
}

pm3::GRID_POINT pm3::GRID_POINT::operator- (const pm3::GRID_POINT &p) const {
    return pm3::GRID_POINT( m_layer - p.m_layer, m_point - p.m_point );
}

pm3::GRID_POINT pm3::GRID_POINT::operator* (float f) const {
    return pm3::GRID_POINT( m_layer * f, m_point * f );
}

pm3::GRID_POINT pm3::GRID_POINT::operator/ (float f) const {
    return pm3::GRID_POINT( m_layer / f, m_point / f );
}

pm3::GRID_POINT& pm3::GRID_POINT::operator+= (const pm3::GRID_POINT &p) {
    m_layer += p.m_layer;
    m_point += p.m_point;
    return *this;
}

pm3::GRID_POINT& pm3::GRID_POINT::operator-= (const pm3::GRID_POINT &p) {
    m_layer -= p.m_layer;
    m_point -= p.m_point;
    return *this;
}

pm3::GRID_POINT& pm3::GRID_POINT::operator*= (float f) {
    m_layer *= f;
    m_point *= f;
    return *this;
}

pm3::GRID_POINT& pm3::GRID_POINT::operator/= (float f) {
    m_layer /= f;
    m_point /= f;
    return *this;
}

Ogre::Vector3 pm3::GRID_POINT::to_vec() const {
    return Ogre::Vector3( m_point.x, m_layer, m_point.y );
}

template class pm3::VEC2<int>;
template class pm3::VEC2<float>;

